package com.chinasoft.obj;

import com.alibaba.fastjson.JSON;
import com.chinasoft.enumdef.Direction;
import com.chinasoft.enumdef.Elem;
import com.chinasoft.ui.GamePanel;
import lombok.Data;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

@Data
public class MapData {
    public final int WIDTH = 20;
    public final int MAX_LEVEL = 50;
    // 地图数组
    Elem[][] map = new Elem[WIDTH][WIDTH];
    Elem[][] bkMap = new Elem[WIDTH][WIDTH];
    // 当前的level
    int level = 1;
    Man man;
    // 箱子的列表
    List<Box> boxList = new ArrayList<>();
    BoxGroup group = new BoxGroup(this);

    public MapData() {
        SaveConfig sc = readConfig();
        if (sc == null) {
            this.level = 1;
        } else {
            this.level = sc.getLevel();
        }
        initMap();
//        this.level = 1;
        readCurrentMap();
        this.man = createManFromMap();
        // 创建箱子对象
        initBoxList();
    }

    private void initMap() {
        for(int y = 0; y < this.WIDTH; y++) {
            for (int x = 0; x < this.WIDTH; x++) {
                map[y][x] = Elem.Glass;
            }
        }
    }

    public Elem setElem(int y, int x, Elem e) {
        Elem bk = this.map[y][x];
        this.map[y][x] = e;
        return bk;
    }

    public Elem getElem(int y, int x) {
//        if (y >= this.WIDTH)
        return this.map[y][x];
    }

    private SaveConfig readConfig() {
        // get json file
        String path = GamePanel.class.getResource("/").getPath() + "/save" ;
        System.out.println(path);
        String filename = path + "/config.json";
        // 删除文件
        File configFile = new File(filename);
        if (configFile.exists()) {
            try {
                FileReader fr = new FileReader(configFile);

                char[] buffer = new char[2048];
                int len = fr.read(buffer);
                String jsonStr = new String(buffer, 0, len);
                SaveConfig saveConfig = JSON.parseObject(jsonStr, SaveConfig.class);
//                this.level = saveConfig.getLevel();
                return saveConfig;
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
//            this.level = 1;
            return null;
        }
        return null;
    }

    private void initBoxList() {
        // 清空
        boxList.clear();
        for(int y = 0; y < WIDTH; y++) {
            for(int x = 0; x < WIDTH; x++) {
                // 是否是 人
                if (map[y][x] == Elem.Box) {
                    // 创建箱子对象
                    Box box = new Box(x, y,  this);
                    // 将对象加入列表
                    boxList.add(box);
                } else if (map[y][x] == Elem.BoxGold) {
                    // 创建箱子对象
                    Box box = new Box(x, y, this);
                    // 箱子里面有 金子
                    box.setContain(Elem.Gold);
                    // 将对象加入列表
                    boxList.add(box);
                }
            }
        }
    }

    /**
     * 读下一关地图
     */
    public boolean nextLevel() {
        this.level ++;
        if (this.level > MAX_LEVEL) {
            return false;
        } else {
            readCurrentMap();
            this.man = createManFromMap();
            initBoxList();
            return true;
        }
    }

    public boolean gotoLevel(int level) {
        this.level = level;
        if (this.level > MAX_LEVEL) {
            return false;
        } else {
            readCurrentMap();
            this.man = createManFromMap();
            initBoxList();
            return true;
        }
    }
    public boolean loadLevel() {
        SaveConfig sc = readConfig();
        this.level = sc.getLevel();
        if (this.level > MAX_LEVEL) {
            return false;
        } else {
            readSaveMap();
            this.man = createManFromSc(sc);
            initBoxList();
            return true;
        }
    }

    private Man createManFromSc(SaveConfig sc) {
        Man m = new Man();
        m.setManX(sc.getX());
        m.setManY(sc.getY());
        // 设置 map对象
        m.setMap(this.map);
        // 设置 MapData对象
        m.setData(this);
        m.setManDir(Direction.Down);
        // 在地图里面设置人
        m.setManBk(this.map[sc.getY()][sc.getX()]);
        this.map[sc.getY()][sc.getX()] = Elem.Man;
        return m;
    }

    private void readSaveMap() {
        initMap();
        readMap(this.level, "save");
    }


    public void readCurrentMap() {
        initMap();
        readMap(this.level, "maps");
    }


    public void readMap(int level, String dir) {
        try {
            // 普通文本读入流
            FileReader fr = new FileReader(GamePanel.class.getResource("/" + dir +"/" + level + ".map").getPath());
            // 缓冲流
            BufferedReader br = new BufferedReader(fr);
            // 读入一行
            String line = br.readLine();
            int y = 0;
            // 读文件的全部
            while(line != null) {
                System.out.println(line);
                char[] chars = line.toCharArray();
                for(int x = 0; x < chars.length; x++) {
                    int val = Integer.parseInt("" + chars[x]);
                    if (val == 2) {
                        val = 0;
                    }
                    map[y][x] = Elem.getElemFromVal(val);
                }
                line = br.readLine();
                y++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void writeMap(int level, Elem[][] arrMap) {
        try {
            String path = GamePanel.class.getResource("/").getPath() + "/save" ;
            System.out.println(path);
            File dir = new File(path);
            if (dir.exists() == false) {
                dir.mkdir();
            }
            String filename = path + "/" + level + ".map";
            // 删除文件
            File saveFile = new File(filename);
            if (saveFile.exists()) {
                saveFile.delete();
            }
            FileWriter fw = new FileWriter(saveFile);
            BufferedWriter bw = new BufferedWriter(fw);
            StringBuffer sb = new StringBuffer();
            for(int y = 0; y < WIDTH; y++) {
                sb.delete(0, sb.length());
                for(int x = 0; x < WIDTH; x++) {
                    sb.append("" + arrMap[y][x].getVal());
                }
                bw.write(sb.toString());
                bw.newLine();
            }
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取地图里面人的位置
     */
    public Man createManFromMap() {
        for(int y = 0; y < WIDTH; y++) {
            for(int x = 0; x < WIDTH; x++) {
                // 是否是 人
                if (map[y][x] == Elem.Man) {
                    Man m = new Man();
                    m.setManX(x);
                    m.setManY(y);
                    // 设置 map对象
                    m.setMap(this.map);
                    // 设置 MapData对象
                    m.setData(this);
                    m.setManDir(Direction.Down);
                    return m;
                }
            }
        }
        return new Man();
    }

    /**
     * 通过 x,y 去找到 箱子对象
     * @param x : 箱子的x
     * @param y
     * @return: 找到的箱子
     */
    public Box findBox(int x, int y) {
        for (Box box : boxList) {
            if (box.getX() == x && box.getY() == y) {
                return box;
            }
        }
        System.out.println("no box found");
        return null;
//        throw new RuntimeException("没有找到箱子  " + x + ", " + y);
    }

    public boolean isPushGroup(Direction dr) {
        Elem obj = man.getNextBox(dr).getNextObj(dr);

        if (obj == Elem.Box || obj == Elem.BoxGold) {
            return true;
        } else {
            return false;
        }
    }

    public Elem getNextCode(Object obj, Direction dr) {
        int x = 0, y = 0;
        if (obj instanceof Man) {
            Man m = (Man) obj;
            x = m.getManX();
            y = m.getManY();
        } else if (obj instanceof Box) {
            Box b = (Box) obj;
            x = b.getX();
            y = b.getY();
        } else {
            throw new RuntimeException("invalid object " + obj);
        }
        switch (dr) {
            case Up:
                y--;
                break;
            case Down:
                y++;
                break;
            case Left:
                x--;
                break;
            case Right:
                x++;
                break;
        }
        return map[y][x];
    }

    public Box getNextBox(Object obj, Direction dr) {
        int x = 0, y = 0;
        if (obj instanceof Man) {
            Man m = (Man) obj;
            x = m.getManX();
            y = m.getManY();
        } else if (obj instanceof Box) {
            Box b = (Box) obj;
            x = b.getX();
            y = b.getY();
        } else {
            throw new RuntimeException("invalid object " + obj);
        }
        switch (dr) {
            case Up :
                y--;
                break;
            case Down:
                y++;
                break;
            case Left:
                x--;
                break;
            case Right:
                x++;
                break;
        }
        return findBox(x, y);
    }

    /*该方法用于保存当前游戏进度。
    首先检查是否已有更高级别的存档，若无则继续；
    将当前地图复制到备份数组，写入地图文件；
    再将玩家位置和关卡信息序列化为JSON格式，保存至[config.json](file://C:\ws_sg\game07best\target\classes\save\config.json)文件中。*/
    public void saveCurrent() {
        System.out.println("-----in save Current ---------");
        SaveConfig sc = readConfig();
        if (sc != null && sc.getLevel() > this.level) {
            // 保存高级别的 level，就是level不变
            System.out.println("不保存 低级 level");
            return;
        }
        dupliate(map, bkMap);
        writeMap(this.level, this.bkMap);
        SaveConfig saveConfig = new SaveConfig(man.getManX(), man.getManY(), this.level);
        String jsonStr = JSON.toJSONString(saveConfig);
        System.out.println(jsonStr);
        // get json file
        String path = GamePanel.class.getResource("/").getPath() + "save" ;
        System.out.println(path);
        File dir = new File(path);
        if (dir.exists() == false) {
            dir.mkdir();
        }
        String filename = path + "/config.json";
        System.out.println("filename is:" +  filename);
        // 删除文件
        File saveFile = new File(filename);
        if (saveFile.exists()) {
            saveFile.delete();
        }
        try {
            FileWriter fw = new FileWriter(saveFile);
            fw.write(jsonStr);
            fw.flush();
            fw.close();
            System.out.println("写文件完成 ！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void dupliate(Elem[][] map, Elem[][] bkMap) {
        for(int y = 0; y < WIDTH; y++) {
            for(int x = 0; x < WIDTH; x++) {
                // 是否是 人
                if (map[y][x] == Elem.Man ) {
                    bkMap[y][x] = man.getManBk();
                } else {
                    bkMap[y][x] = map[y][x];
                }
            }
        }
    }

    public boolean isWin() {
        boolean winFlag = true;
        for (Box b : boxList) {
            if (b.isOk() == false) {
                winFlag = false;
                return winFlag;
            }
        }
        return winFlag;
    }
}
